package jblip.gui.components.tree;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;

import jblip.BlipClient;
import jblip.gui.JBlip;
import jblip.gui.JBlipClient;
import jblip.gui.data.channels.BliposphereChannel;
import jblip.gui.data.channels.DashboardChannel;
import jblip.gui.data.channels.DataChannel;
import jblip.gui.data.channels.TagDataChannel;
import jblip.gui.data.channels.UserDataChannel;
import jblip.resources.Subscription;
import jblip.resources.Update;

public class ChannelTreeModel extends DefaultTreeModel implements Observer {
  private static final long serialVersionUID = 1L;

  public ChannelTreeModel() {
    super(new DefaultMutableTreeNode());

    final BliposphereChannel bliposphere = DataChannel.getBliposphereChannel();
    bliposphere.addObserver(this);

    final DashboardChannel dashboard = DataChannel.getDashboardChannel();
    dashboard.addObserver(this);

    final DataChannel<Update> users = new DataChannel<Update>("Użytkownicy");
    final ChannelTreeNode<Update> users_node =
        new ChannelTreeNode<Update>(this, users);

    final DataChannel<Update> tags = new DataChannel<Update>("Tagi");
    final ChannelTreeNode<Update> tags_node =
        new ChannelTreeNode<Update>(this, tags);

    final MutableTreeNode mutable_root = (MutableTreeNode) root;

    insertNodeInto(new UpdatesChannelNode(this, bliposphere), mutable_root, 0);
    insertNodeInto(new UpdatesChannelNode(this, dashboard), mutable_root, 1);
    insertNodeInto(users_node, mutable_root, 2);
    insertNodeInto(tags_node, mutable_root, 3);

    final BlipClient client = JBlip.instance().getBlipClient();

    Enumeration<? extends Subscription> subs = null;

    while (subs == null) {
      // TODO: need better solution for failing API
      subs = client.getSubscriptionsFrom(null);
    }

    final SortedSet<String> usernames = new TreeSet<String>();
    while (subs.hasMoreElements()) {
      usernames.add(subs.nextElement().getTrackedUserName());
    }

    int user_index = 0;
    for (String user : usernames) {
      final UserDataChannel data = DataChannel.getUserChannel(user);
      data.addObserver(this);
      users_node.insert(new UserChannelNode(this, data), user_index++);
    }

    // TODO: when API provides tags tracking, change this
    final SortedSet<String> tagnames = new TreeSet<String>();
    tagnames.addAll(((JBlipClient)client).getTrackedTags());

    int tag_index = 0;
    for (String tagname : tagnames) {
      final TagDataChannel data = DataChannel.getTagChannel(tagname);
      data.addObserver(this);
      tags_node.insert(new TagChannelNode(this, data), tag_index++);
    }
  }

  @SuppressWarnings("unchecked")
  synchronized List<ChannelTreeNode<Serializable>> getRootChildren() {
    final int count = root.getChildCount();
    ArrayList<ChannelTreeNode<Serializable>> children =
        new ArrayList<ChannelTreeNode<Serializable>>(count);
    for (int i = 0; i < count; i++) {
      children.add((ChannelTreeNode<Serializable>) root.getChildAt(i));
    }

    return children;
  }

  @Override
  public void update(Observable o, Object arg) {
    if (arg instanceof Iterable<?>) {
      Iterator<?> iter = ((Iterable<?>) arg).iterator();
      int count = 0;
      while (iter.hasNext()) {
        iter.next();
        count++;
      }
      if (count > 0) {
        System.err.println("Received " + count + " new updates");
      }
    } else {
      System.err.println("Got invalid update: " + arg);
    }
  }
}
